package models

import (
	"time"

	"gorm.io/datatypes"
	"gorm.io/gorm"
)

// Order 订单表
type Order struct {
	BaseModel
	OrderNo         string         `gorm:"size:32;not null;uniqueIndex;comment:订单编号" json:"order_no"`
	UserID          uint           `gorm:"not null;index;comment:用户ID" json:"user_id"`
	TotalAmount     float64        `gorm:"type:decimal(10,2);not null;comment:订单总金额" json:"total_amount"`
	PaymentAmount   float64        `gorm:"type:decimal(10,2);not null;comment:实付金额" json:"payment_amount"`
	FreightAmount   float64        `gorm:"type:decimal(10,2);default:0;comment:运费" json:"freight_amount"`
	DiscountAmount  float64        `gorm:"type:decimal(10,2);default:0;comment:优惠金额" json:"discount_amount"`
	CouponID        *string        `gorm:"size:32;comment:优惠券ID" json:"coupon_id,omitempty"`
	PaymentMethod   *string        `gorm:"type:enum('wechat','alipay','balance');comment:支付方式" json:"payment_method,omitempty"`
	PaymentTime     *time.Time     `gorm:"autoPaymentTime;comment:支付时间" json:"payment_time,omitempty"`
	Status          string         `gorm:"type:enum('pending_payment','paid','shipped','completed','cancelled','refunded');default:'pending_payment';index;comment:订单状态" json:"status"`
	ShippingAddress datatypes.JSON `gorm:"type:json;not null;comment:收货地址" json:"shipping_address"`
	Note            *string        `gorm:"size:500;comment:订单备注" json:"note,omitempty"`

	// 关联关系
	Items []OrderItem `gorm:"foreignKey:OrderID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"items,omitempty"`
	User  User        `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-"`
}

func (o *Order) FindByRawSQL(db *gorm.DB, query string, args ...interface{}) error {
	//TODO implement me
	panic("implement me")
}

// Order 订单表 CRUD 实现
func (o *Order) Create(db *gorm.DB) error {
	// 订单创建时自动关联订单商品（事务保证数据一致性）
	return db.Transaction(func(tx *gorm.DB) error {
		// 1. 创建订单主表
		if err := tx.Create(o).Error; err != nil {
			return err
		}
		// 2. 批量创建订单商品（若有商品项）
		if len(o.Items) > 0 {
			for i := range o.Items {
				o.Items[i].OrderID = o.ID // 绑定订单ID
			}
			if err := tx.CreateInBatches(o.Items, len(o.Items)).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

func (o *Order) Update(db *gorm.DB) error {
	// 订单状态更新时，避免修改不可变字段（如订单编号、用户ID）
	updatableFields := map[string]interface{}{
		"payment_amount":   o.PaymentAmount,
		"freight_amount":   o.FreightAmount,
		"discount_amount":  o.DiscountAmount,
		"coupon_id":        o.CouponID,
		"payment_method":   o.PaymentMethod,
		"payment_time":     o.PaymentTime,
		"status":           o.Status,
		"shipping_address": o.ShippingAddress,
		"note":             o.Note,
	}
	return db.Model(o).Select(updatableFields).Updates(updatableFields).Error
}

func (o *Order) Delete(db *gorm.DB, id uint) error {
	// 级联删除订单及关联的订单商品（事务保证）
	return db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Where("order_id = ?", id).Delete(&OrderItem{}).Error; err != nil {
			return err
		}
		return tx.Delete(&Order{}, id).Error
	})
}

func (o *Order) GetByID(db *gorm.DB, id uint) error {
	// 预加载关联的订单商品，避免N+1查询
	return db.Preload("Items.Product").First(o, id).Error
}

func (o *Order) List(db *gorm.DB, page, pageSize int) ([]interface{}, int64, error) {
	var total int64
	var orders []Order

	// 构建查询条件（支持按用户ID、订单状态筛选）
	query := db.Model(&Order{})
	if o.UserID > 0 {
		query = query.Where("user_id = ?", o.UserID)
	}
	if o.Status != "" {
		query = query.Where("status = ?", o.Status)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询（预加载订单商品）
	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Preload("Items").Find(&orders).Error; err != nil {
		return nil, 0, err
	}

	// 转换为接口切片返回
	result := make([]interface{}, len(orders))
	for i, v := range orders {
		result[i] = v
	}
	return result, total, nil
}

func (o *Order) GetByField(db *gorm.DB, field string, value interface{}) error {
	result := db.Where(map[string]interface{}{field: value}).First(o)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// OrderItem 订单商品
type OrderItem struct {
	BaseModel
	OrderID      uint           `gorm:"not null;index;comment:订单ID" json:"order_id"`
	ProductID    uint           `gorm:"not null;index;comment:商品ID" json:"product_id"`
	ProductName  string         `gorm:"size:100;not null;comment:商品名称" json:"product_name"`
	ProductImage *string        `gorm:"size:255;comment:商品图片" json:"product_image,omitempty"`
	Specs        datatypes.JSON `gorm:"type:json;comment:规格属性" json:"specs"`
	Price        float64        `gorm:"type:decimal(10,2);not null;comment:单价" json:"price"`
	Quantity     int            `gorm:"not null;comment:购买数量" json:"quantity"`
	Subtotal     float64        `gorm:"type:decimal(10,2);not null;comment:小计金额" json:"subtotal"`

	// 关联关系
	Order   Order   `gorm:"foreignKey:OrderID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-"`
	Product Product `gorm:"foreignKey:ProductID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"product,omitempty"`
}

// OrderItem 订单商品 CRUD 实现
func (oi *OrderItem) Create(db *gorm.DB) error {
	return db.Create(oi).Error
}

func (oi *OrderItem) Update(db *gorm.DB) error {
	// 订单商品仅允许修改规格、单价、数量（小计需重新计算）
	oi.Subtotal = oi.Price * float64(oi.Quantity)
	return db.Model(oi).Updates(map[string]interface{}{
		"specs":         oi.Specs,
		"price":         oi.Price,
		"quantity":      oi.Quantity,
		"subtotal":      oi.Subtotal,
		"product_image": oi.ProductImage,
	}).Error
}

func (oi *OrderItem) Delete(db *gorm.DB, id uint) error {
	return db.Delete(&OrderItem{}, id).Error
}

func (oi *OrderItem) GetByID(db *gorm.DB, id uint) error {
	return db.Preload("Product").First(oi, id).Error
}

func (oi *OrderItem) List(db *gorm.DB, page, pageSize int) ([]interface{}, int64, error) {
	var total int64
	var items []OrderItem

	// 支持按订单ID、商品ID筛选
	query := db.Model(&OrderItem{})
	if oi.OrderID > 0 {
		query = query.Where("order_id = ?", oi.OrderID)
	}
	if oi.ProductID > 0 {
		query = query.Where("product_id = ?", oi.ProductID)
	}

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Preload("Product").Find(&items).Error; err != nil {
		return nil, 0, err
	}

	result := make([]interface{}, len(items))
	for i, v := range items {
		result[i] = v
	}
	return result, total, nil
}

// Cart 购物车
type Cart struct {
	BaseModel
	UserID    uint           `gorm:"not null;index;comment:用户ID" json:"user_id"`
	ProductID uint           `gorm:"not null;index;comment:商品ID" json:"product_id"`
	Specs     datatypes.JSON `gorm:"type:json;comment:规格" json:"specs"`
	Quantity  int            `gorm:"default:1;comment:数量" json:"quantity"`
	Selected  bool           `gorm:"default:true;comment:是否选中" json:"selected"`

	// 关联关系
	User    User    `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-"`
	Product Product `gorm:"foreignKey:ProductID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"product"`
}

func (c *Cart) FindByRawSQL(db *gorm.DB, query string, args ...interface{}) error {
	//TODO implement me
	panic("implement me")
}

func (c *Cart) GetByField(db *gorm.DB, field string, value interface{}) error {
	result := db.Where(map[string]interface{}{field: value}).First(c)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// Cart 购物车 CRUD 实现
func (c *Cart) Create(db *gorm.DB) error {
	// 同一用户+同一商品+同一规格，不重复创建（更新数量）
	var existCart Cart
	if err := db.Where("user_id = ? AND product_id = ? AND specs = ?", c.UserID, c.ProductID, c.Specs).First(&existCart).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return db.Create(c).Error // 不存在则创建
		}
		return err
	}
	// 存在则更新数量（累加）
	existCart.Quantity += c.Quantity
	return db.Model(&existCart).Update("quantity", existCart.Quantity).Error
}

func (c *Cart) Update(db *gorm.DB) error {
	// 支持更新数量、选中状态、规格
	return db.Model(c).Updates(map[string]interface{}{
		"quantity": c.Quantity,
		"selected": c.Selected,
		"specs":    c.Specs,
	}).Error
}

func (c *Cart) Delete(db *gorm.DB, id uint) error {
	return db.Delete(&Cart{}, id).Error
}

func (c *Cart) GetByID(db *gorm.DB, id uint) error {
	return db.Preload("Product").First(c, id).Error
}

func (c *Cart) List(db *gorm.DB, page, pageSize int) ([]interface{}, int64, error) {
	var total int64
	var carts []Cart

	// 必按用户ID筛选（购物车属于个人），支持按选中状态筛选
	query := db.Model(&Cart{}).Where("user_id = ?", c.UserID)
	if c.Selected {
		query = query.Where("selected = ?", c.Selected)
	}

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Preload("Product").Find(&carts).Error; err != nil {
		return nil, 0, err
	}

	result := make([]interface{}, len(carts))
	for i, v := range carts {
		result[i] = v
	}
	return result, total, nil
}

// Coupon 优惠活动
type Coupon struct {
	BaseModel
	Name       string         `gorm:"type:varchar(100);not null;comment:名称"`
	Code       string         `gorm:"type:varchar(50);uniqueIndex;comment:兑换码"`
	Discount   float64        `gorm:"type:decimal(10,2);comment:折扣金额/比例"`
	MinAmount  float64        `gorm:"type:decimal(10,2);comment:最低使用金额"`
	StartAt    time.Time      `gorm:"comment:生效时间"`
	EndAt      time.Time      `gorm:"comment:过期时间"`
	IsGlobal   bool           `gorm:"comment:是否全场通用"`
	ProductIDs datatypes.JSON `gorm:"type:json;comment:指定商品ID列表"`
}

func (cp *Coupon) FindByRawSQL(db *gorm.DB, query string, args ...interface{}) error {
	//TODO implement me
	panic("implement me")
}

func (cp *Coupon) GetByField(db *gorm.DB, field string, value interface{}) error {
	result := db.Where(map[string]interface{}{field: value}).First(cp)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// 4. Coupon 优惠活动 CRUD 实现
func (cp *Coupon) Create(db *gorm.DB) error {
	// 校验优惠券有效期（生效时间<=过期时间）
	if cp.StartAt.After(cp.EndAt) {
		return gorm.ErrInvalidData
	}
	return db.Create(cp).Error
}

func (cp *Coupon) Update(db *gorm.DB) error {
	// 支持更新名称、折扣、使用门槛、有效期、适用商品
	return db.Model(cp).Updates(map[string]interface{}{
		"name":        cp.Name,
		"discount":    cp.Discount,
		"min_amount":  cp.MinAmount,
		"start_at":    cp.StartAt,
		"end_at":      cp.EndAt,
		"is_global":   cp.IsGlobal,
		"product_ids": cp.ProductIDs,
	}).Error
}

func (cp *Coupon) Delete(db *gorm.DB, id uint) error {
	return db.Delete(&Coupon{}, id).Error
}

func (cp *Coupon) GetByID(db *gorm.DB, id uint) error {
	return db.First(cp, id).Error
}

func (cp *Coupon) List(db *gorm.DB, page, pageSize int) ([]interface{}, int64, error) {
	var total int64
	var coupons []Coupon

	// 支持按是否全场通用、有效期筛选
	query := db.Model(&Coupon{})
	if cp.IsGlobal {
		query = query.Where("is_global = ?", cp.IsGlobal)
	}
	// 筛选当前有效的优惠券（可选）
	now := time.Now()
	query = query.Where("start_at <= ? AND end_at >= ?", now, now)

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Find(&coupons).Error; err != nil {
		return nil, 0, err
	}

	result := make([]interface{}, len(coupons))
	for i, v := range coupons {
		result[i] = v
	}
	return result, total, nil
}

// InventoryLog 库存流水
type InventoryLog struct {
	BaseModel
	ProductID  string  `gorm:"type:varchar(32);index;comment:商品ID"`
	OrderID    *string `gorm:"type:varchar(32);index;comment:关联订单ID"`
	Change     int     `gorm:"comment:变动数量(正数入库,负数出库)"`
	FinalStock int     `gorm:"comment:变动后库存"`
	Operator   string  `gorm:"type:varchar(32);comment:操作人"`
}

func (il *InventoryLog) FindByRawSQL(db *gorm.DB, query string, args ...interface{}) error {
	//TODO implement me
	panic("implement me")
}

func (il *InventoryLog) GetByField(db *gorm.DB, field string, value interface{}) error {
	result := db.Where(map[string]interface{}{field: value}).First(il)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// 5. InventoryLog 库存流水 CRUD 实现
func (il *InventoryLog) Create(db *gorm.DB) error {
	// 库存流水不可修改，创建时需校验变动逻辑（如出库不能导致负库存）
	return db.Create(il).Error
}

func (il *InventoryLog) Update(db *gorm.DB) error {
	// 库存流水为日志类数据，禁止更新（仅允许创建和查询）
	return gorm.ErrInvalidTransaction
}

func (il *InventoryLog) Delete(db *gorm.DB, id uint) error {
	// 日志类数据禁止删除（如需清理需走归档逻辑）
	return gorm.ErrInvalidTransaction
}

func (il *InventoryLog) GetByID(db *gorm.DB, id uint) error {
	return db.First(il, id).Error
}

func (il *InventoryLog) List(db *gorm.DB, page, pageSize int) ([]interface{}, int64, error) {
	var total int64
	var logs []InventoryLog

	// 支持按商品ID、订单ID、操作人筛选
	query := db.Model(&InventoryLog{})
	if il.ProductID != "" {
		query = query.Where("product_id = ?", il.ProductID)
	}
	if il.OrderID != nil && *il.OrderID != "" {
		query = query.Where("order_id = ?", *il.OrderID)
	}
	if il.Operator != "" {
		query = query.Where("operator = ?", il.Operator)
	}

	// 按创建时间倒序（最新日志在前）
	query = query.Order("created_at DESC")

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Find(&logs).Error; err != nil {
		return nil, 0, err
	}

	result := make([]interface{}, len(logs))
	for i, v := range logs {
		result[i] = v
	}
	return result, total, nil
}
